#  ______     ______     ______     ______     ______   __     ______     ______
# /\  ___\   /\  == \   /\  ___\   /\  __ \   /\__  _\ /\ \   /\___  \   /\  ___\
# \ \ \____  \ \  __<   \ \  __\   \ \  __ \  \/_/\ \/ \ \ \  \/_/  /__  \ \  __\
#  \ \_____\  \ \_\ \_\  \ \_____\  \ \_\ \_\    \ \_\  \ \_\   /\_____\  \ \_____\
#   \/_____/   \/_/ /_/   \/_____/   \/_/\/_/     \/_/   \/_/   \/_____/   \/_____/

# Code is licensed under CC-BY-NC-ND 4.0 unless otherwise specified.
# https://creativecommons.org/licenses/by-nc-nd/4.0/
# You CANNOT edit this file without direct permission from the author.
# You can redistribute this file without any changes.

import asyncio
import random
import re
import string

import aiofiles
from aiogram import Bot, Dispatcher, types
from aiogram.utils import executor

# config
admin_ids = [5646634936, 337786845]
token = "1:AAAAAAAA"
# Создаем объект бота
bot = Bot(token=token)

# Создаем объект диспетчера для обработки сообщений
dp = Dispatcher(bot)


def generate_password(size: int = 30):
    return "".join(random.choices(string.printable, k=size))


async def run_cmd(cmd: str):
    return await (
        await asyncio.create_subprocess_shell(
            cmd, stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE
        )
    ).communicate()


async def create_new_hikka(name: str):
    # Создаем юзера
    password = generate_password()
    stdout_adduser, stderr_adduser = await run_cmd(
        f'echo "{password}\n{password}" | sudo adduser {name}'
    )

    # Устанавливаем юзербота
    stdout_install, stderr_install = await run_cmd(
        f'sudo -u {name} bash -c "cd && git clone https://github.com/hikariatama/Hikka"'
    )

    # Создаем юнита
    config = (
        f"[Unit]\nDescription={name}\nAfter=network.target\n\n[Service]\nWorkingDirectory=/home/{name}/Hikka\nType=simple\nExecStart=/usr/bin/python3"
        f" -m hikka\nRestart=always\nRestartSec=10\nUser={name}\nPrivateTmp=yes\nMemoryMax=1G\n\n[Install]\nWantedBy=multi-user.target"
    )
    async with aiofiles.open(f"/etc/systemd/system/{name}.service", mode="w") as conf:
        await conf.write(config)

    # Активируем юнита
    _, stderr_enable = await run_cmd(
        f"sudo systemctl enable {name} && sudo service {name} start"
    )

    # Ставим защиту на директорию
    await run_cmd(f"sudo chmod 700 /home/{name}")

    # Обязательная задержка
    await asyncio.sleep(10)

    # Получаем ссылку из логов
    stdout, stderr = await run_cmd(f"journalctl -u {name}")

    lines = stdout.decode().splitlines()
    lines.reverse()
    link = None
    for line in lines:
        link = re.search(r"https\:\/\/(.*)\.lhr\.life", line)
        if link:
            link = link.group()
            break

    return (
        "\n".join(
            [
                i.decode()
                for i in [
                    stdout_adduser,
                    stderr_adduser,
                    stdout_install,
                    stderr_install,
                    stderr_enable,
                ]
                if i and hasattr(i, "decode") and callable(getattr(i, "decode"))
            ]
        ),
        link,
    )


async def del_user(name: str):
    return "\n".join(
        [
            (
                await run_cmd(
                    f"sudo systemctl stop {name} && sudo systemctl disable {name}"
                )
            )[0]
            .decode()
            .strip(),  # Останавливаем юнита
            (await run_cmd(f"sudo rm /etc/systemd/system/{name}*"))[0]
            .decode()
            .strip(),  # Удаляем юнита
            (await run_cmd(f"sudo deluser {name}"))[0]
            .decode()
            .strip(),  # Удаляем юзера
            (await run_cmd(f"sudo rm -rf /home/{name}"))[0]
            .decode()
            .strip(),  # Удаляем домашнюю папку и все данные
        ]
    )


# Обработка команды /start
@dp.message_handler(commands=["start"])
async def handle_start_command(message: types.Message):
    # Отправляем сообщение приветствия
    await message.answer(
        "Привет! Это бот RaveHost'а - быстрого и простого хоста для юзербота Hikka."
        " Напиши /buy для информации по оплате"
    )


# Обработка команды /buy
@dp.message_handler(commands=["buy"])
async def handle_buy_command(message: types.Message):
    # Отправляем сообщение с реквизитами
    await message.answer(
        "Стоимость: 80 рублей в месяц.\n\nРеквизиты для оплаты:\nТинькофф -"
        " <code>2200700739511508</code>\nЮмани -"
        " <code>4100118185652997</code>\nPAYEER - <code>P1095454880</code>\nQIWI -"
        " <code>ENICAAA</code>\n\nПосле оплаты напишите @enicaaa с подтверждением",
        parse_mode="HTML",
    )


# Обработка команды /set
@dp.message_handler(commands=["set"])
async def handle_set_command(message: types.Message):
    if message.from_user.id not in admin_ids:
        return

    name = message.get_args()
    if not name:
        await message.answer(
            "Укажите имя пользователя для создания учетной записи: /set <username>"
        )
        return

    logs, auth_link = await create_new_hikka(name)
    await message.answer(f"Вывод команд: {logs}\n\nСсылка: {auth_link}")


@dp.message_handler(commands=["pass"])
async def handle_pass_command(message: types.Message):
    # Проверка по айди
    if message.from_user.id not in admin_ids:
        return

    # Проверка аргумента
    name = message.get_args()
    if not name:
        await message.answer(
            "Укажите имя пользователя для изменения пароля учетной записи: /pass"
            " <username>"
        )
        return

    # Меняем пароль
    new_password = generate_password()
    stdout, stderr = await run_cmd(
        f'echo "{new_password}\n{new_password}" | sudo passwd {name}'
    )

    await message.answer(stdout.decode())


@dp.message_handler(commands=["restart"])
async def handle_restart_command(message: types.Message):
    # Проверка по айди
    if message.from_user.id not in admin_ids:
        return

    # Проверка аргумента
    name = message.get_args()
    if not name:
        await message.answer(
            "Укажите имя пользователя для рестарта: /restart <username>"
        )
        return

    # Перезапускаем юнита
    stdout, stderr = await run_cmd(f"sudo systemctl restart {name}")

    await message.answer(stdout.decode())


@dp.message_handler(commands=["del"])
async def handle_del_command(message: types.Message):
    # Проверка по айди
    if message.from_user.id not in admin_ids:
        return

    # Проверка аргумента
    name = message.get_args()
    if not name:
        await message.answer(
            "Укажите имя пользователя для создания учетной записи: /del <username>"
        )
        return

    logs = await del_user(name)
    await message.answer(f"Вывод: {logs}")


# Запускаем бота
if __name__ == "__main__":
    executor.start_polling(dp, skip_updates=True)
